import json
import uuid
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser
from django.core.paginator import Paginator
from django.utils import timezone
from django.db.models import Q
from .lib.Neo4jServices import *

from .serializers import GraphSerializer
from drf_spectacular.utils import extend_schema, OpenApiExample,OpenApiParameter, OpenApiResponse
from drf_spectacular.types import OpenApiTypes
from rest_framework.decorators import action
from .lib.Neo4jServices import Neo4jServices
from rest_framework.views import APIView
from django.core.cache import caches, cache  # 导入 caches
from loguru import logger  # 使用 loguru 的 logger
from urllib.parse import quote  # 用于转义缓存键

# 配置 loguru 日志
logger.add("logs/app.log", rotation="100 MB")  # 自动分割日志文件，最大 100MB
# 封装缓存操作逻辑
def get_cached_data(cache_key):
    try:
        cached_data = cache.get(cache_key)  # 更改为使用 cache
        if cached_data:
            return json.loads(cached_data)  # 反序列化
    except Exception as e:
        logger.error(f"Error accessing Redis cache: {e}")
    return None

def set_cached_data(cache_key, data, timeout=3600):
    try:
        cache.set(cache_key, json.dumps(data), timeout)  # 更改为使用 cache
    except Exception as e:
        logger.error(f"Error setting Redis cache: {e}")

@extend_schema(tags = ["Neo4j图谱"])
class GraphNeo4jView(viewsets.ModelViewSet):#APIView):
    """图谱API"""
    permission_classes = [AllowAny]
    serializer_class = GraphSerializer
    queryset = []  # 或具体 queryset
    industryNameMapping = {
        '人参':'人参',
        '新材料':'碳纤维',
    }
    @extend_schema(
        operation_id = "获取行业图谱",
        summary = "获取特定行业的图谱",
        # 执行序列化器
        responses={200: Response()},
        parameters = [
            OpenApiParameter(name = "industryName",description = "行业名称",type = OpenApiTypes.STR,required = True,enum = ['人参', '新材料'],default="人参"),
            OpenApiParameter(name = "patent_top_n",description = "专利TopN",type = OpenApiTypes.NUMBER,required = False,default="10"),
            OpenApiParameter(name = "maxLevel",description = "图谱层级",type = OpenApiTypes.NUMBER,required = False,default="2"),
            OpenApiParameter(name = "limit",description = "图谱节点数量限制",type = OpenApiTypes.NUMBER,required = False,default="-1"),
            OpenApiParameter(name = "topK",description = "图谱topK关键词",type = OpenApiTypes.NUMBER,required = False,default="30"),
            OpenApiParameter(name = "refresh",description = "是否刷新缓存数据",type = OpenApiTypes.NUMBER,required = False,default="0"),
        ]
    )
    @action(detail=False, methods=['get'])
    def get(self, request):
        time_start = time.time()
        industryName= request.query_params.get('industryName', "人参")
        industryName= self.industryNameMapping.get(industryName)
        if industryName is None:
            return Response({
                'message':'Not Found Industry Name.',
                'code': 200,
                'data': {
                    'total': 0,
                    'topK':[],
                    'nodes':[],
                    'relationships':[]
                    }
                }
            )
        patent_top_n = int(request.query_params.get('patent_top_n', '10'))
        maxLevel = int(request.query_params.get('maxLevel', 2))
        limit = int(request.query_params.get('limit', -1))
        topK = int(request.query_params.get('topK', '30'))
        refresh = request.query_params.get('refresh', '0')

        # 构建缓存的唯一key（对 industryName 进行转义）
        cache_key = f"industry_graph_{quote(industryName)}_{maxLevel}_{limit}_{topK}_{patent_top_n}"

        # 检查是否需要刷新缓存
        if refresh == '1':
            cache.delete(cache_key)  # 使用 cache.delete 删除旧的缓存数据

        # 尝试从缓存获取数据
        cached_data = get_cached_data(cache_key)
        if cached_data:
            time_end = time.time()
            time_cost = 1000*(time_end-time_start)
            logger.info("get for key {},cost {}ms".format(cache_key,time_cost))
            return Response({
                'code': 200,
                'data': cached_data
            })

        # 从 Neo4j中读取数据
        #TODO 测试用户名和密码，后续注意放到配置文件加密
        NEO4J_CONFIG = {
            "uri": "neo4j://81.70.135.187:37687",
            "user": "neo4j",
            "password": "vPn**12@@56"
        }
        try:
            app = Neo4jServices(**NEO4J_CONFIG)
            nodes,relationships,topK_ = app.get_all_entities_relationships_with_industry_for_topK(industryName,patent_top_n=patent_top_n,maxLevel=maxLevel,limit=limit,topN_limit=topK)
            # 将取得的结果存入缓存
            result_data = {
                'total': 0,
                'topK': topK_,
                'nodes': nodes,
                'relationships': relationships
            }
            set_cached_data(cache_key, result_data, None)  # 此处的 None 表示不超时
        except Exception as e:
            import traceback
            traceback.print_exc()

            logger.error("Exception {} when request for {}".format(e,industryName))
        finally:
            app.close()
        time_end = time.time()
        time_cost = 1000*(time_end-time_start)
        logger.info("get for key {},cost {}ms".format(cache_key,time_cost))
        return Response({
            'code': 200,
            'data': {
                'total': 0,
                'topK':topK_,
                'nodes':nodes,
                'relationships':relationships
                }
            }
        )

    @extend_schema(
        operation_id = "获取文档图谱",
        summary = "获取特定专利论文政策资讯的图谱",
        # 执行序列化器
        responses={200: Response()},
        parameters = [
            OpenApiParameter(name = "original_ids",description = "专利论文政策资讯的IDs列表",type = OpenApiTypes.STR,required = True,
                examples=[OpenApiExample('例子',summary='ID列表',description='专利论文政策资讯的ID的列表',value="['135613802','66868871']"),]),
            OpenApiParameter(name = "maxLevel",description = "图谱层级",type = OpenApiTypes.NUMBER,required = False,default="3"),
            OpenApiParameter(name = "limit",description = "图谱节点数量限制",type = OpenApiTypes.NUMBER,required = False,default="-1"),
        ]
    )
    @action(detail=False, methods=['get'])
    def retreive(self, request):
        original_ids = request.query_params.get('original_ids', [])
        logger.debug("request for {}".format(original_ids))
        maxLevel = int(request.query_params.get('maxLevel', 3))
        limit = int(request.query_params.get('limit', -1))
        # 从 Neo4j中读取数据
        #TODO 测试用户名和密码，后续注意放到配置文件加密
        NEO4J_CONFIG = {
            "uri":"neo4j://81.70.135.187:37687",
            "user":"neo4j",
            "password":"vPn**12@@56"
        }
        try:
            app = Neo4jServices(**NEO4J_CONFIG)
            nodes,relationships = app.get_all_entities_relationships_with_es_id(original_ids,maxLevel=maxLevel,limit=limit)
        except Exception as e:
            import traceback
            traceback.print_exc()
            logger.error("Exception {} when request for {}".format(e,original_ids))
        finally:
            app.close()
        return Response({
            'code': 200,
            'data': {
                'total': 0,
                'nodes':nodes,
                'relationships':relationships
                }
            }
        )
